package deploy

import (
	"bsinpass/go/mpc/blockchain/cfx/cfxerc1155"
	"bsinpass/go/mpc/blockchain/cfx/cfxerc721"
	"bsinpass/go/mpc/blockchain/client"
	"bsinpass/go/mpc/blockchain/contract/hello"
	"bsinpass/go/mpc/common"
	"context"
	"crypto/ecdsa"
	"fmt"
	"log"
	"math/big"
	"time"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/crypto"
)

var txConf = &common.GlobalConf
var txLog = common.GetNftLog("deploy")

func Deploy() {

}

func DeployHelloOnEth(reqChain, caller, callerprivatekey string) (string, string, common.NftError) {
	// get eth client
	client, nftErr := client.GetEthClient(reqChain)
	if !common.Valid(nftErr) {
		txLog.LogE("Get cfx client failed! [%v]", nftErr.ErrorMsg)
		return "", "", nftErr
	}
	privateKey, err := crypto.HexToECDSA(callerprivatekey)
	if err != nil {
		log.Fatal(err)
	}
	publicKey := privateKey.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
	}
	fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
	// Get Wallet Nonce
	nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Transaction nonce: %d \n", nonce)
	// Get estimated gasPrice
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Suggested gasPrice: %d \n", gasPrice)

	// Get estimated gasPrice
	gasLimit, err := client.SuggestGasTipCap(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Suggested gasLimit: %d \n", gasLimit)

	auth := bind.NewKeyedTransactor(privateKey)
	auth.Nonce = big.NewInt(int64(nonce))
	auth.Value = big.NewInt(0)      // in wei
	auth.GasLimit = uint64(1000000) // in units
	// auth.GasLimit = gasLimit

	auth.GasPrice = gasPrice
	address, tx, instance, err := hello.DeployHello(auth, client)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Deployed to address: https://rinkeby.etherscan.io/address/%v \n", address.Hex())
	fmt.Printf("Deployed at transaction https://rinkeby.etherscan.io/tx/%v \n", tx.Hash().Hex())
	_ = instance
	fmt.Println("deploy hash:\n", tx.Hash().Hex())
	fmt.Println("deploy contract address:\n", address.Hex())

	return tx.Hash().Hex(), tx.Hash().Hex(), common.NewError(200)
}

func DeployErc721OnCfx(reqChain, totalsupply, name, symbol, baseuri, caller, callerprivatekey string) (string, string, common.NftError, string, string) {
	tsupply, ok := big.NewInt(0).SetString(totalsupply, 10)
	if !ok {
		txLog.LogE("Input totalsupply [%v] not correct!", totalsupply)
		return "", "", common.NewError(405), "", ""
	}
	// get cfx client
	client, nftErr := client.GetCfxClient(reqChain)
	if !common.Valid(nftErr) {
		txLog.LogE("Get cfx client failed! [%v]", nftErr.ErrorMsg)
		return "", "", nftErr, "", ""
	}

	accounts := client.AccountManager.List()
	fmt.Println("accounts-----------------11111:\n", accounts)

	for _, account := range accounts {
		client.AccountManager.Delete(account, txConf.PassWord)
		fmt.Println("delete account:", account)
	}

	address, err := txConf.AccountManager.ImportKey(callerprivatekey, txConf.PassWord)
	fmt.Println("import address: ", address)
	if err != nil {
		txLog.LogE("Cfx Import to keystore failed! [%v]", err)
		// return "", common.NewError(511)
	}

	accounts = client.AccountManager.List()
	fmt.Println("accounts--------22222:\n", accounts)
	err = client.AccountManager.UnlockDefault(txConf.PassWord)
	if err != nil {
		txLog.LogE("UnlockDefault failed! [%v]", err)
		return "", "", common.NewError(511), "", ""
	}

	// if account.GetCfxCurrentAccounts() == nil {
	// 	fmt.Println("Get cfx current account failed!")
	// 	_, err := account.CfxImportAccount(common.GlobalConf.PrivateKey)
	// 	if err != nil {
	// 		return "", "", common.NewError(509)
	// 	}
	// }
	fmt.Println("deploy from:\n", client.AccountManager.List())
	tx, hash, _, err := cfxerc721.DeployCfxerc721(nil, client, tsupply, name, symbol, baseuri)
	if err != nil {
		fmt.Println(err)
		return "", "", common.NewError(509), "", ""
	}

	// *types.TransactionReceipt
	receipt, err := client.WaitForTransationReceipt(*hash, time.Second)
	if err != nil {
		return "", "", common.NewError(510), "", ""
	}

	// logrus.WithFields(logrus.Fields{
	// 	"tx":               tx,
	// 	"hash":             hash,
	// 	"contract address": receipt.ContractCreated,
	// }).Info("deploy token done")

	fmt.Println("deploy hash:\n", hash.String())
	fmt.Println("deploy contract address:\n", receipt.ContractCreated.String())

	outTx := fmt.Sprintf("%v", tx)
	fmt.Println("outTx: ", outTx)
	outRecipt := fmt.Sprintf("%v", receipt)
	fmt.Println("outRecipt: ", outRecipt)
	return hash.String(), receipt.ContractCreated.String(), common.NewError(200), outTx, outRecipt
}

func Deploy1155OnCfx(reqChain, totalsupply, name, symbol, baseuri, caller, callerprivatekey string) (string, string, common.NftError, string, string) {
	tsupply, ok := big.NewInt(0).SetString(totalsupply, 10)
	if !ok {
		txLog.LogE("Input totalsupply [%v] not correct!", totalsupply)
		return "", "", common.NewError(405), "", ""
	}
	// get cfx client
	client, nftErr := client.GetCfxClient(reqChain)
	if !common.Valid(nftErr) {
		txLog.LogE("Get cfx client failed! [%v]", nftErr.ErrorMsg)
		return "", "", nftErr, "", ""
	}

	accounts := client.AccountManager.List()
	fmt.Println("accounts-----------------11111:\n", accounts)

	for _, account := range accounts {
		client.AccountManager.Delete(account, txConf.PassWord)
		fmt.Println("delete account:", account)
	}

	address, err := txConf.AccountManager.ImportKey(callerprivatekey, txConf.PassWord)
	fmt.Println("import address: ", address)
	if err != nil {
		txLog.LogE("Cfx Import to keystore failed! [%v]", err)
		// return "", common.NewError(511)
	}

	accounts = client.AccountManager.List()
	fmt.Println("accounts--------22222:\n", accounts)
	err = client.AccountManager.UnlockDefault(txConf.PassWord)
	if err != nil {
		txLog.LogE("UnlockDefault failed! [%v]", err)
		return "", "", common.NewError(511), "", ""
	}

	fmt.Println("deploy from:\n", client.AccountManager.List())
	tx, hash, _, err := cfxerc1155.DeployCfxerc1155(nil, client, tsupply, name, symbol, baseuri)
	if err != nil {
		fmt.Println(err)
		return "", "", common.NewError(509), "", ""
	}

	// *types.TransactionReceipt
	receipt, err := client.WaitForTransationReceipt(*hash, time.Second)
	if err != nil {
		return "", "", common.NewError(510), "", ""
	}

	// logrus.WithFields(logrus.Fields{
	// 	"tx":               tx,
	// 	"hash":             hash,
	// 	"contract address": receipt.ContractCreated,
	// }).Info("deploy token done")

	fmt.Println("deploy hash:\n", hash.String())
	fmt.Println("deploy contract address:\n", receipt.ContractCreated.String())

	outTx := fmt.Sprintf("%v", tx)
	fmt.Println("outTx: ", outTx)
	outRecipt := fmt.Sprintf("%v", receipt)
	fmt.Println("outRecipt: ", outRecipt)
	return hash.String(), receipt.ContractCreated.String(), common.NewError(200), outTx, outRecipt
}
